<!DOCTYPE html>
<!-- saved from url=(0058)https://online.pragmaticstudio.com/courses/elixir/steps/59 -->
<html lang="en-US" class="book"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  
  <title>The Pragmatic Studio Online | Developing with Elixir/OTP</title>
  <link rel="apple-touch-icon-precomposed" sizes="144x144" href="https://online.pragmaticstudio.com/favicons/apple-touch-icon-144x144.png">
  <link rel="apple-touch-icon-precomposed" sizes="152x152" href="https://online.pragmaticstudio.com/favicons/apple-touch-icon-152x152.png">
  <link rel="icon" type="image/png" href="https://online.pragmaticstudio.com/favicons/favicon-32x32.png" sizes="32x32">
  <link rel="icon" type="image/png" href="https://online.pragmaticstudio.com/favicons/favicon-16x16.png" sizes="16x16">
  <link rel="shortcut icon" href="https://online.pragmaticstudio.com/favicons/favicon.ico">
  <link rel="stylesheet" media="all" href="./27The Pragmatic Studio Online _ Developing with Elixir_OTP_files/application-cb185c07f9e7cf3071c019ec9ae89c92.css">
  <script async="" src="./27The Pragmatic Studio Online _ Developing with Elixir_OTP_files/analytics.js.завантаження"></script><script src="./27The Pragmatic Studio Online _ Developing with Elixir_OTP_files/application-dc521b896b294cf4648f0cd28001e154.js.завантаження"></script>
  
  <meta name="csrf-param" content="authenticity_token">
<meta name="csrf-token" content="cKgZjuwjXzvRdeDWAdzXAKxC3PmEVh66tP9coQsTYTAboTzcHE8Z8Rz/DPP7Yv4NG3AxTY5/Z3Idw6hhpCRUKA==">
    <script type="text/javascript">
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-59927351-1', 'auto');
  ga('send', 'pageview');
</script>

</head>
<body>
  <div id="header">
    <div id="logo">
      <a title="Pragmatic Studio Online" href="https://online.pragmaticstudio.com/"><img alt="Pragmatic Studio Online" title="Pragmatic Studio Online" src="./27The Pragmatic Studio Online _ Developing with Elixir_OTP_files/logo-a167560d29b6afb905c24a3432045f34.png"></a>
    </div>
    <div id="site_links">
      <ul>
        <li>
          <a href="https://pragmaticstudio.com/my_account">my courses</a>
        </li>
        <li>•</li>
        <li>
          <a href="https://online.pragmaticstudio.com/signout">sign out</a>
        </li>
      </ul>
    </div>
  </div>
  <div id="main_wrapper_1">
    <div id="main_wrapper_2">
      <div id="main_wrapper_3">
        <div id="main">
          <div id="content">
            

<h1>Another GenServer</h1>
<h2 class="subtitle">Notes</h2>

<h3>Prepared Code</h3>
<p>
  Here's the <tt>SensorServer</tt> module we already had prepared and walked through at the start of the video:
</p>
<div class="highlight"><pre><span class="kd">defmodule</span> <span class="nc">Servy.SensorServer</span> <span class="k">do</span>

  <span class="na">@name</span> <span class="ss">:sensor_server</span>

  <span class="kn">use</span> <span class="nc">GenServer</span>

  <span class="c1"># Client Interface</span>

  <span class="kd">def</span> <span class="n">start</span> <span class="k">do</span>
    <span class="nc">GenServer</span><span class="p">.</span><span class="n">start</span><span class="p">(</span><span class="bp">__MODULE__</span><span class="p">,</span> <span class="p">%{},</span> <span class="ss">name</span><span class="p">:</span> <span class="na">@name</span><span class="p">)</span>
  <span class="k">end</span>

  <span class="kd">def</span> <span class="n">get_sensor_data</span> <span class="k">do</span>
    <span class="nc">GenServer</span><span class="p">.</span><span class="n">call</span> <span class="na">@name</span><span class="p">,</span> <span class="ss">:get_sensor_data</span>
  <span class="k">end</span>

  <span class="c1"># Server Callbacks</span>

  <span class="kd">def</span> <span class="n">init</span><span class="p">(</span><span class="n">_state</span><span class="p">)</span> <span class="k">do</span>
    <span class="n">initial_state</span> <span class="p">=</span> <span class="n">run_tasks_to_get_sensor_data</span><span class="p">()</span>
    <span class="p">{</span><span class="ss">:ok</span><span class="p">,</span> <span class="n">initial_state</span><span class="p">}</span>
  <span class="k">end</span>

  <span class="kd">def</span> <span class="n">handle_call</span><span class="p">(</span><span class="ss">:get_sensor_data</span><span class="p">,</span> <span class="n">_from</span><span class="p">,</span> <span class="n">state</span><span class="p">)</span> <span class="k">do</span>
    <span class="p">{</span><span class="ss">:reply</span><span class="p">,</span> <span class="n">state</span><span class="p">,</span> <span class="n">state</span><span class="p">}</span>
  <span class="k">end</span>

  <span class="kd">defp</span> <span class="n">run_tasks_to_get_sensor_data</span> <span class="k">do</span>
    <span class="nc">IO</span><span class="p">.</span><span class="n">puts</span> <span class="s2">"Running tasks to get sensor data..."</span>

    <span class="n">task</span> <span class="p">=</span> <span class="nc">Task</span><span class="p">.</span><span class="n">async</span><span class="p">(</span><span class="k">fn</span> <span class="p">-&gt;</span> <span class="nc">Servy.Tracker</span><span class="p">.</span><span class="n">get_location</span><span class="p">(</span><span class="s2">"bigfoot"</span><span class="p">)</span> <span class="k">end</span><span class="p">)</span>

    <span class="n">snapshots</span> <span class="p">=</span>
      <span class="p">[</span><span class="s2">"cam-1"</span><span class="p">,</span> <span class="s2">"cam-2"</span><span class="p">,</span> <span class="s2">"cam-3"</span><span class="p">]</span>
      <span class="o">|&gt;</span> <span class="nc">Enum</span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">&amp;</span><span class="nc">Task</span><span class="p">.</span><span class="n">async</span><span class="p">(</span><span class="k">fn</span> <span class="p">-&gt;</span> <span class="nc">Servy.VideoCam</span><span class="p">.</span><span class="n">get_snapshot</span><span class="p">(</span><span class="ni">&amp;1</span><span class="p">)</span> <span class="k">end</span><span class="p">))</span>
      <span class="o">|&gt;</span> <span class="nc">Enum</span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">&amp;</span><span class="nc">Task</span><span class="p">.</span><span class="n">await</span><span class="o">/</span><span class="mi">1</span><span class="p">)</span>

    <span class="n">where_is_bigfoot</span> <span class="p">=</span> <span class="nc">Task</span><span class="p">.</span><span class="n">await</span><span class="p">(</span><span class="n">task</span><span class="p">)</span>

    <span class="p">%{</span><span class="ss">snapshots</span><span class="p">:</span> <span class="n">snapshots</span><span class="p">,</span> <span class="ss">location</span><span class="p">:</span> <span class="n">where_is_bigfoot</span><span class="p">}</span>
  <span class="k">end</span>
<span class="k">end</span>
</pre></div>

<h3>Handling Unexpected Messages</h3>
<p>
  In the video we defined the following <tt>handle_info</tt> function clause:
</p>
<div class="highlight"><pre><span class="kd">def</span> <span class="n">handle_info</span><span class="p">(</span><span class="ss">:refresh</span><span class="p">,</span> <span class="n">_state</span><span class="p">)</span> <span class="k">do</span>
  <span class="nc">IO</span><span class="p">.</span><span class="n">puts</span> <span class="s2">"Refreshing the cache..."</span>
  <span class="n">new_state</span> <span class="p">=</span> <span class="n">run_tasks_to_get_sensor_data</span><span class="p">()</span>
  <span class="n">schedule_refresh</span><span class="p">()</span>
  <span class="p">{</span><span class="ss">:noreply</span><span class="p">,</span> <span class="n">new_state</span><span class="p">}</span>
<span class="k">end</span>
</pre></div>
<p>
  You'll recall from the previous section that <tt>use GenServer</tt> injects a default <tt>handle_info</tt> implementation that logs unexpected messages.
  But it's important to note that once you define a <tt>handle_info</tt> function for a specific message such as <tt>:refresh</tt>, the default implementation is over-written. 
</p>
<p>
  So if you also want to handle unexpected messages, then you'll need to add a function clause that matches all unexpected messages:
</p>
<div class="highlight"><pre><span class="kd">def</span> <span class="n">handle_info</span><span class="p">(</span><span class="n">unexpected</span><span class="p">,</span> <span class="n">state</span><span class="p">)</span> <span class="k">do</span>
  <span class="nc">IO</span><span class="p">.</span><span class="n">puts</span> <span class="s2">"Can't touch this! </span><span class="si">#{</span><span class="n">inspect</span> <span class="n">unexpected</span><span class="si">}</span><span class="s2">"</span>
  <span class="p">{</span><span class="ss">:noreply</span><span class="p">,</span> <span class="n">state</span><span class="p">}</span>
<span class="k">end</span>
</pre></div>
<p>
  Make sure to put it <em>below</em> all the other <tt>handle_info</tt> functions!
</p>

<h3>Exercise: Dynamically Change the Refresh Interval</h3>
<p>
  In the video we used a module attribute to set the refresh interval as a constant. But suppose you want to be able to change that interval while the server is running. For example, given a <tt>set_refresh_interval/1</tt> client interface function, the refresh interval could be changed to 5 minutes like so:
</p>
<div class="highlight"><pre><span class="nc">Servy.SensorServer</span><span class="p">.</span><span class="n">set_refresh_interval</span><span class="p">(</span><span class="ss">:timer</span><span class="p">.</span><span class="n">minutes</span><span class="p">(</span><span class="mi">5</span><span class="p">))</span>
</pre></div>
<p>
  And then at some point later the interval could be throttled back to something like 2 hours:
</p>
<div class="highlight"><pre><span class="nc">Servy.SensorServer</span><span class="p">.</span><span class="n">set_refresh_interval</span><span class="p">(</span><span class="ss">:timer</span><span class="p">.</span><span class="n">hours</span><span class="p">(</span><span class="mi">2</span><span class="p">))</span>
</pre></div>
<p>
  Sounds like a useful feature, right? Make it so by changing the <tt>SensorServer</tt> to include a <tt>set_refresh_interval/1</tt> function that dynamically changes the refresh interval. To do that, you'll need to keep the refresh interval in the state of the process. Currently the state consists of a map of sensor data. So you might find it handy to define a <tt>State</tt> struct with two fields—one for the sensor data and one for the refresh interval—with each having default values. For example:
</p>
<div class="highlight"><pre><span class="kd">defmodule</span> <span class="nc">State</span> <span class="k">do</span>
  <span class="kd">defstruct</span> <span class="ss">sensor_data</span><span class="p">:</span> <span class="p">%{},</span> 
            <span class="ss">refresh_interval</span><span class="p">:</span> <span class="ss">:timer</span><span class="p">.</span><span class="n">minutes</span><span class="p">(</span><span class="mi">60</span><span class="p">)</span>
<span class="k">end</span>
</pre></div>
      <div class="toggle">
                <p>
          <a class="button show-hide" href="javascript:void(0)" rel="nofollow">
            <span class="title">Show Answer</span>
          </a>
        </p>
      <p style="display:none;">
        <a class="button show-hide" href="javascript:void(0)" rel="nofollow">
          <span class="title">Hide Answer</span>
        </a>
      </p>

        <div style="display:none;">
          
          <div class="highlight"><pre><span class="kd">defmodule</span> <span class="nc">Servy.SensorServer</span> <span class="k">do</span>

  <span class="na">@name</span> <span class="ss">:sensor_server</span>

  <span class="kn">use</span> <span class="nc">GenServer</span>

  <span class="kd">defmodule</span> <span class="nc">State</span> <span class="k">do</span>
    <span class="kd">defstruct</span> <span class="ss">sensor_data</span><span class="p">:</span> <span class="p">%{},</span> 
              <span class="ss">refresh_interval</span><span class="p">:</span> <span class="ss">:timer</span><span class="p">.</span><span class="n">minutes</span><span class="p">(</span><span class="mi">60</span><span class="p">)</span>
  <span class="k">end</span>

  <span class="c1"># Client Interface</span>

  <span class="kd">def</span> <span class="n">start</span> <span class="k">do</span>
    <span class="nc">IO</span><span class="p">.</span><span class="n">puts</span> <span class="s2">"Starting the sensor server..."</span>
    <span class="nc">GenServer</span><span class="p">.</span><span class="n">start</span><span class="p">(</span><span class="bp">__MODULE__</span><span class="p">,</span> <span class="p">%</span><span class="nc">State</span><span class="p">{},</span> <span class="ss">name</span><span class="p">:</span> <span class="na">@name</span><span class="p">)</span>
  <span class="k">end</span>

  <span class="kd">def</span> <span class="n">get_sensor_data</span> <span class="k">do</span>
    <span class="nc">GenServer</span><span class="p">.</span><span class="n">call</span> <span class="na">@name</span><span class="p">,</span> <span class="ss">:get_sensor_data</span>
  <span class="k">end</span>

  <span class="kd">def</span> <span class="n">set_refresh_interval</span><span class="p">(</span><span class="n">time_in_ms</span><span class="p">)</span> <span class="k">do</span>
    <span class="nc">GenServer</span><span class="p">.</span><span class="n">cast</span> <span class="na">@name</span><span class="p">,</span> <span class="p">{</span><span class="ss">:set_refresh_interval</span><span class="p">,</span> <span class="n">time_in_ms</span><span class="p">}</span>
  <span class="k">end</span>
  
  <span class="c1"># Server Callbacks</span>

  <span class="kd">def</span> <span class="n">init</span><span class="p">(</span><span class="n">state</span><span class="p">)</span> <span class="k">do</span>
    <span class="n">sensor_data</span> <span class="p">=</span> <span class="n">run_tasks_to_get_sensor_data</span><span class="p">()</span>
    <span class="n">initial_state</span> <span class="p">=</span> <span class="p">%{</span><span class="n">state</span> <span class="p">|</span> <span class="ss">sensor_data</span><span class="p">:</span> <span class="n">sensor_data</span><span class="p">}</span>
    <span class="n">schedule_refresh</span><span class="p">(</span><span class="n">state</span><span class="p">.</span><span class="n">refresh_interval</span><span class="p">)</span>
    <span class="p">{</span><span class="ss">:ok</span><span class="p">,</span> <span class="n">initial_state</span><span class="p">}</span>
  <span class="k">end</span>

  <span class="kd">def</span> <span class="n">handle_cast</span><span class="p">({</span><span class="ss">:set_refresh_interval</span><span class="p">,</span> <span class="n">time_in_ms</span><span class="p">},</span> <span class="n">state</span><span class="p">)</span> <span class="k">do</span>
    <span class="n">new_state</span> <span class="p">=</span> <span class="p">%{</span> <span class="n">state</span> <span class="p">|</span> <span class="ss">refresh_interval</span><span class="p">:</span> <span class="n">time_in_ms</span> <span class="p">}</span>
    <span class="n">schedule_refresh</span><span class="p">(</span><span class="n">new_state</span><span class="p">.</span><span class="n">refresh_interval</span><span class="p">)</span>
    <span class="p">{</span><span class="ss">:noreply</span><span class="p">,</span> <span class="n">new_state</span><span class="p">}</span>
  <span class="k">end</span>

  <span class="kd">def</span> <span class="n">handle_info</span><span class="p">(</span><span class="ss">:refresh</span><span class="p">,</span> <span class="n">state</span><span class="p">)</span> <span class="k">do</span>
    <span class="nc">IO</span><span class="p">.</span><span class="n">puts</span> <span class="s2">"Refreshing the cache..."</span>
    <span class="n">sensor_data</span> <span class="p">=</span> <span class="n">run_tasks_to_get_sensor_data</span><span class="p">()</span>
    <span class="n">new_state</span> <span class="p">=</span> <span class="p">%{</span> <span class="n">state</span> <span class="p">|</span> <span class="ss">sensor_data</span><span class="p">:</span> <span class="n">sensor_data</span><span class="p">}</span>
    <span class="n">schedule_refresh</span><span class="p">(</span><span class="n">state</span><span class="p">.</span><span class="n">refresh_interval</span><span class="p">)</span>
    <span class="p">{</span><span class="ss">:noreply</span><span class="p">,</span> <span class="n">new_state</span><span class="p">}</span>
  <span class="k">end</span>

  <span class="kd">defp</span> <span class="n">schedule_refresh</span><span class="p">(</span><span class="n">time_in_ms</span><span class="p">)</span> <span class="k">do</span>
    <span class="nc">Process</span><span class="p">.</span><span class="n">send_after</span><span class="p">(</span><span class="n">self</span><span class="p">(),</span> <span class="ss">:refresh</span><span class="p">,</span> <span class="n">time_in_ms</span><span class="p">)</span>    
  <span class="k">end</span>

  <span class="kd">def</span> <span class="n">handle_call</span><span class="p">(</span><span class="ss">:get_sensor_data</span><span class="p">,</span> <span class="n">_from</span><span class="p">,</span> <span class="n">state</span><span class="p">)</span> <span class="k">do</span>
    <span class="p">{</span><span class="ss">:reply</span><span class="p">,</span> <span class="n">state</span><span class="p">.</span><span class="n">sensor_data</span><span class="p">,</span> <span class="n">state</span><span class="p">}</span>
  <span class="k">end</span>

  <span class="kd">defp</span> <span class="n">run_tasks_to_get_sensor_data</span> <span class="k">do</span>
    <span class="nc">IO</span><span class="p">.</span><span class="n">puts</span> <span class="s2">"Running tasks to get sensor data..."</span>

    <span class="n">task</span> <span class="p">=</span> <span class="nc">Task</span><span class="p">.</span><span class="n">async</span><span class="p">(</span><span class="k">fn</span> <span class="p">-&gt;</span> <span class="nc">Servy.Tracker</span><span class="p">.</span><span class="n">get_location</span><span class="p">(</span><span class="s2">"bigfoot"</span><span class="p">)</span> <span class="k">end</span><span class="p">)</span>

    <span class="n">snapshots</span> <span class="p">=</span>
      <span class="p">[</span><span class="s2">"cam-1"</span><span class="p">,</span> <span class="s2">"cam-2"</span><span class="p">,</span> <span class="s2">"cam-3"</span><span class="p">]</span>
      <span class="o">|&gt;</span> <span class="nc">Enum</span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">&amp;</span><span class="nc">Task</span><span class="p">.</span><span class="n">async</span><span class="p">(</span><span class="k">fn</span> <span class="p">-&gt;</span> <span class="nc">Servy.VideoCam</span><span class="p">.</span><span class="n">get_snapshot</span><span class="p">(</span><span class="ni">&amp;1</span><span class="p">)</span> <span class="k">end</span><span class="p">))</span>
      <span class="o">|&gt;</span> <span class="nc">Enum</span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">&amp;</span><span class="nc">Task</span><span class="p">.</span><span class="n">await</span><span class="o">/</span><span class="mi">1</span><span class="p">)</span>

    <span class="n">where_is_bigfoot</span> <span class="p">=</span> <span class="nc">Task</span><span class="p">.</span><span class="n">await</span><span class="p">(</span><span class="n">task</span><span class="p">)</span>

    <span class="p">%{</span><span class="ss">snapshots</span><span class="p">:</span> <span class="n">snapshots</span><span class="p">,</span> <span class="ss">location</span><span class="p">:</span> <span class="n">where_is_bigfoot</span><span class="p">}</span>
  <span class="k">end</span>
<span class="k">end</span>
</pre></div>
        </div>
      </div>


<h3>Exercise: Background Jobs On Your Project?</h3>
<p>
  Do you have scheduled background jobs on your project that perhaps you could encapsulate within a GenServer? For example, maybe you need to poll a filesystem directory for new files, parse the file data when it arrives, and report on the success or failure. Or perhaps you need to send a "heartbeat" at periodic intervals or even ping other services periodically. Give it some thought.
</p>

<h3>Code So Far</h3>
<p>
  The code for this video is in the
<code>another-genserver</code> directory found within the
  <tt>video-code</tt> directory of the <a href="https://s3.amazonaws.com/pragmaticstudio/courses/elixir/pragstudio-elixir-code.zip">code bundle</a>.
</p>



<div class="chapter_navigation bottom">
  
    <a class="multi-line-button green" href="https://online.pragmaticstudio.com/courses/elixir/steps/742/achievements" data-method="post" rel="nofollow" style="width:16em">
      <span class="title">Go To Next Video</span>
      <span class="subtitle">and mark this step complete!</span>
    </a>
    
</div>



  



            <div id="footer">
              <p>
  All course material, including videos, slides, and source code, is copyrighted and licensed for
  <em>individual use only</em>. You may make copies for your own personal use (e.g. on your laptop, on your
  iPad, on your backup drive). However, you may not transfer ownership or share the material with other
  people. We make no guarantees that the source code is fit for any purpose. Course material may not be
  used to create training material, courses, books, and the like. Please support us and our instructors by
  encouraging others to purchase their own copies. Thank you!
</p>

              <p>
                Copyright © 2005–2018, The Pragmatic Studio.
                All Rights Reserved.
              </p>
            </div>
          </div>
          <div id="sidebar">
            <div class="course_head">
  <h3>Developing with Elixir/OTP</h3>
  <h4 class="subtitle"></h4>
</div>
<div class="progress">
  <div class="meter">
    <div class="meter_progress" style="width: 0%"></div>
  </div>
  <div class="meter_label">
    0% complete
  </div>
  <div class="meter_reset">
    
  </div>
</div>
<div class="navigation">
  <ul>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/1">1. Introduction</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/1">Video</a><span class="time">1:56</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/2">Setup</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/2">2. Create Mix Project</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/3">Video</a><span class="time">8:21</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/4">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/3">3. High-Level Transformations</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/5">Video</a><span class="time">8:27</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/6">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/4">4. Parse Request Line</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/7">Video</a><span class="time">10:21</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/8">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/5">5. Route and Response</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/9">Video</a><span class="time">6:40</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/10">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/6">6. Function Clauses</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/11">Video</a><span class="time">6:28</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/12">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/7">7. Request Params and Status Codes</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/13">Video</a><span class="time">8:45</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/14">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/8">8. Rewrite Paths and Track 404s</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/15">Video</a><span class="time">9:31</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/16">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/9">9. Serve Static Files</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/17">Video</a><span class="time">11:27</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/18">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/10">10. Module Attributes</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/19">Video</a><span class="time">3:00</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/20">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/11">11. Organizing Code</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/21">Video</a><span class="time">6:30</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/22">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/12">12. Modeling With Structs</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/23">Video</a><span class="time">11:09</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/24">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/13">13. Handle POST Requests</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/25">Video</a><span class="time">10:32</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/26">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/14">14. Recursion</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/27">Video</a><span class="time">13:17</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/28">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/15">15. Slicing and Dicing with Enum</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/29">Video: Part 1</a><span class="time">10:25</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/30">Video: Part 2</a><span class="time">11:51</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/31">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/16">16. Comprehensions</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/32">Video</a><span class="time">11:15</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/33">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/17">17. A Peek At Phoenix</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/34">Video</a><span class="time">13:12</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/35">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/18">18. Test Automation</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/36">Video</a><span class="time">15:21</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/37">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/19">19. Rendering JSON</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/38">Video</a><span class="time">06:47</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/39">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/20">20. Web Server Sockets</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/40">Video</a><span class="time">19:11</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/41">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/21">21. Concurrent, Isolated Processes</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/42">Video: Part 1</a><span class="time">12:07</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/43">Video: Part 2</a><span class="time">10:21</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/44">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/22">22. Sending and Receiving Messages</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/45">Video</a><span class="time">19:38</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/46">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/23">23. Asynchronous Tasks</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/47">Video</a><span class="time">20:19</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/48">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/24">24. Stateful Server Processes</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/49">Video: Part 1</a><span class="time">8:09</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/50">Video: Part 2</a><span class="time">11:55</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/51">Video: Part 3</a><span class="time">9:49</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/52">Video: Part 4</a><span class="time">8:59</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/53">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/25">25. Refactoring Toward GenServer</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/54">Video</a><span class="time">21:12</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/55">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/26">26. OTP GenServer</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/56">Video</a><span class="time">16:57</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/57">Notes</a></li>
        </ul>
      </li>
      <li class="expanded">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/27">27. Another GenServer</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/58">Video</a><span class="time">9:00</span></li>
            <li class="here"><a href="https://online.pragmaticstudio.com/courses/elixir/steps/59">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/28">28. Linking Processes</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/60">Video</a><span class="time">13:38</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/61">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/29">29. Fault Recovery with OTP Supervisors</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/62">Video: Part 1</a><span class="time">13:39</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/63">Video: Part 2</a><span class="time">6:13</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/64">Notes</a></li>
        </ul>
      </li>
      <li class="">
        <a href="https://online.pragmaticstudio.com/courses/elixir/modules/30">30. Final OTP Application</a>
        <ul>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/65">Video</a><span class="time">15:22</span></li>
            <li class=""><a href="https://online.pragmaticstudio.com/courses/elixir/steps/66">Notes</a></li>
            <li class="not-completable"><a href="https://online.pragmaticstudio.com/courses/elixir/next_steps">Next Steps</a></li>
            <li class="not-completable"><a href="https://online.pragmaticstudio.com/courses/elixir/evaluation">Evaluation</a></li>
        </ul>
      </li>
  </ul>
</div>


          </div>
        </div>
      </div>
    </div>
  </div>


<script id="wappalyzer" src="chrome-extension://gppongmhjkpfnbhagpmjfkannfbllamg/js/inject.js"></script></body></html>